package com.jinke.uang.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * MapEx (可扩展的HashMap)
 * 与Util、JSONUtils关联
 */

@SuppressWarnings("serial")
public class MapEx<K, V> extends HashMap<Object, Object> {

    public MapEx<K, V> set(String key, Object value) {
        this.put(key, value);
        return this;
    }

    public MapEx<K, V> set(String key, String value) {
        this.put(key, value);
        return this;
    }

    public MapEx<K, V> set(String key, int value) {
        return this.set(key, new Integer(value));
    }

    public MapEx<K, V> set(String key, long value) {
        return this.set(key, new Long(value));
    }

    public MapEx<K, V> set(String key, double value) {
        return this.set(key, new Double(value));
    }

    public MapEx<K, V> set(String key, boolean value) {
        return this.set(key, new Boolean(value));
    }

    public MapEx<?, ?> set(String key) {
        return this.set(key, true);
    }

    public MapEx<K, V> unset(String key) {
        this.remove(key);
        return this;
    }

    public String getString(String key) {
        String str = String.valueOf(this.get(key));
        if ("null".equals(str)) return "";
        return str;
    }

    public String getString(String key, String defaultValue) {
        String val = String.valueOf(this.get(key));
        return val == null ? defaultValue : val;
    }

    public int getInteger(String key) {
        Object v = this.get(key);
        if (v == null) return 0;
        try {
            return Integer.parseInt(v.toString());
        } catch (Exception e) {
            return 0;
        }
    }

    public long getLong(String key) {
        Object v = this.get(key);
        if (v == null) return 0;
        try {
            return Long.parseLong(v.toString());
        } catch (Exception e) {
            return 0;
        }
    }

    public double getDouble(String key) {
        Object v = this.get(key);
        if (v == null) return 0;
        try {
            return Double.parseDouble(v.toString());
        } catch (Exception e) {
            return 0;
        }
    }

    public boolean getBoolean(String key) {
        try {
            Boolean v = (Boolean) this.get(key);
            return v.booleanValue();
        } catch (Exception e) {
            return false;
        }
    }

    public Date getDate(String key) {
        try {
            return (Date) this.get(key);
        } catch (Exception e) {
            return null;
        }
    }

    public List<MapEx> getList(Object... args) {
        MapEx map = this;
        List<?> objs = null;
        for (int i = 0; i < args.length; i++) {
            if (i != args.length - 1) {
                map = toMapEx(map.get(args[i]));
                if (map == null) return null;
            } else {
                objs = (List<?>) map.get(args[i]);
                if (objs == null || objs.size() == 0) return null;
            }
        }
        List<MapEx> list = new ArrayList<>();
        for (Object object : objs) {
            MapEx ex = fromMap((Map) object);
            list.add(ex);
        }
        return list;
    }


    public MapEx getMapEx(Object... args) {
        MapEx mapEx = this;
        for (int i = 0; i < args.length; i++) {
            mapEx = toMapEx(this.get(args[i]));
            if (mapEx == null) return null;
        }
        return mapEx;
    }

    public static MapEx toMapEx(Object obj) {
        if (obj == null) return null;
        MapEx mapEx = fromMap((Map) obj);
        return mapEx;
    }

    public MapEx() {

    }

    public MapEx(String key) {
        this.set(key);
    }

    public MapEx(String key, Object value) {
        this.set(key, value);
    }

    public MapEx(String key, long value) {
        this.set(key, value);
    }

    public MapEx(String key, int value) {
        this.set(key, value);
    }

    public MapEx(Object[] keyValuePairs) {
        for (int i = 0; i < keyValuePairs.length; i += 2) {
            Object key = keyValuePairs[i];
            Object val = keyValuePairs[i + 1];
            this.put(key, val);
        }
    }

    public static MapEx<?, ?> create(Object[] keyValuePairs) {
        return new MapEx<Object, Object>(keyValuePairs);
    }

    public static MapEx<?, ?> create(String key, Object value) {
        return new MapEx<Object, Object>(new Object[]{key, value});
    }

    public static MapEx<?, ?> create(String key, long value) {
        return new MapEx<Object, Object>().set(key, value);
    }

    /**
     * 从一个Map实例构建一个MapEx实例
     *
     * @param map
     * @return
     * @update:
     */
    public static MapEx<?, ?> fromMap(Map<?, ?> map) {
        MapEx<?, ?> mapEx = new MapEx<Object, Object>();

        for (Object key : map.keySet()) {
            mapEx.put(key, map.get(key));
        }
        return mapEx;
    }

    /**
     * 从一个Class实例构建一个MapEx实例
     */
    public static MapEx<?, ?> fromClass(Object ot) {
        MapEx<?, ?> mapEx = new MapEx<Object, Object>();
        Field[] fields = ot.getClass().getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            Object value = mapEx.get(fieldName);
            if (value != null) {
                mapEx.put(fieldName, value);
            }
        }
        return mapEx;
    }

    /**
     * 从一个MapEx实例构建一个Class实例
     */
    public <T> T toClass(Class<T> entity) {
        T ot = null;
        try {
            Field[] fields = entity.getDeclaredFields();
            ot = entity.newInstance();
            for (Field field : fields) {
                String fieldName = field.getName();
                Object value = this.get(fieldName);
                if (value != null) {
                    field.setAccessible(true);
                    field.set(ot, value);
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return ot;
    }

}